﻿using iTool.Cloud.Database.ServiceProvider;
using System.IO;
using System.Security.Cryptography;
using System.Text;

using iTool.ClusterComponent;

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace FileCenter.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public partial class StorageController : ControllerBase
    {
        private readonly iToolClusterHostClient _storageService;
        private readonly ILogger<StorageController> _logger;

        public StorageController(iToolClusterHostClient storageService, ILogger<StorageController> logger)
        {
            _storageService = storageService;
            _logger = logger;
        }

        [HttpPost]
        [DisableRequestSizeLimit]
        public async Task<List<string>> UploadFile([FromForm] List<IFormFile> Files)
        {
            List<string> files = new List<string>();
            await Parallel.ForEachAsync(Files, async (file, token) => 
            {
                await using (var stream = file.OpenReadStream())
                {
                    // Step 1 获取文件Key
                    var retVal = MD5.Create().ComputeHash(stream);
                    StringBuilder stringBuilder = new StringBuilder();
                    foreach (var item in retVal)
                    {
                        stringBuilder.Append(item.ToString("x2"));
                    }
                    string fileKey = stringBuilder.ToString();
                    if (files.Contains(fileKey))
                    {
                        files.Add(fileKey);
                        return;
                    }
                    files.Add(fileKey);

                    // Step 2 获取Service
                    iFileService iFileService = _storageService.GetService<iFileService>(fileKey);
                    if (await iFileService.IsExistsAsync())
                    {
                        // 文件已经存在
                        return;
                        //return Results.Ok(fileKey);
                    }


                    // Step 3 定义缓冲区
                    int bufCount = 1024 * 128; // kb
                    byte[] bufs = new byte[stream.Length > bufCount ? bufCount : stream.Length];

                    {
                        // 如果文件小于缓冲区大小，则直接提交
                        if (stream.Length <= bufCount)
                        {
                            stream.Position = 0;
                            await stream.ReadAsync(bufs, 0, (int)stream.Length);
                        }

                        await iFileService.UploadAsync(new UploadInfo
                        {
                            CreateDate = DateTime.Now,
                            FileStream = stream.Length > bufCount ? new byte[0] : bufs,
                            Role = "admin",
                            User = "zxf",
                            SuffixName = Path.GetExtension(file.FileName),
                            TotalLength = stream.Length > bufCount ? 0 : bufs.Length,
                            ContentType= file.ContentType
                        });
                    }

                    // 大文件分片上传
                    if (stream.Length > bufCount)
                    {
                        int index = 0, streamLength = (int)stream.Length, maxPage = (int)Math.Ceiling((decimal)streamLength / bufCount);
                        stream.Position = 0;
                        // 分片
                        while (true)
                        {
                            int sequence = await stream.ReadAsync(bufs, 0, bufCount);
                            if (sequence == 0) {
                                break;
                            }
                            index++;
                            await iFileService.UploadPieceAsync(new UploadPiece
                            {
                                Number = index,
                                FileStream = bufs.Take(sequence).ToArray(),
                                IsEndNUmber = index == maxPage
                            });
                        }

                        await iFileService.UploadComplatedAsync();
                    }
                }
            });

            return files;
        }

        [HttpGet("{id}")]
        public async Task<object> DownLoadFile(string id)
        {
            iFileService iFileService = _storageService.GetService<iFileService>(id);
            var info = await iFileService.GetFileInfoAsync();

            MemoryStream fileStream = new MemoryStream(info.TotalLength);

            if (info.UploadState == 200)
            {
                var file = await iFileService.GetStreamAsync();
                await fileStream.WriteAsync(file.FileStream, 0, file.FileStream.Length);
            }
            else if (info.UploadState == 201)
            {
                int page = 0;
                while (true)
                {
                    page++;
                    var file = await iFileService.GetStreamAsync(page);
                    await fileStream.WriteAsync(file.FileStream, 0, file.FileStream.Length);
                    if (file.IsEndNUmber)
                    {
                        break;
                    }
                }
            }
            else
            {
                return Results.Ok();
            }
            this.Response.ContentLength = info.TotalLength;
            this.Response.Headers.Add("Accept-Ranges", "bytes");
            this.Response.Headers.Add("Content-Range", "bytes 0-" + info.TotalLength);
            fileStream.Position = 0;
            return File(fileStream, info.ContentType, string.Format("{0}{1}", id, info.SuffixName));
        }

        [HttpGet("{id}/view")]
        public async Task<FileStreamResult> DownloadView(string id)
        {
            iFileService iFileService = _storageService.GetService<iFileService>(id);
            var info = await iFileService.GetFileInfoAsync();
            if (info.UploadState < 200)
            {
                return default;
            }
            MemoryStream fileStream = new MemoryStream(info.TotalLength);
            int page = 0;
            while (true)
            {
                page++;
                var file = await iFileService.GetStreamAsync(page);
                await fileStream.WriteAsync(file.FileStream, 0, file.FileStream.Length);
                if (file.IsEndNUmber)
                {
                    break;
                }
            }
            this.Response.ContentLength = info.TotalLength;
            this.Response.Headers.Add("Accept-Ranges", "bytes");
            this.Response.Headers.Add("Content-Range", "bytes 0-" + info.TotalLength);
            fileStream.Position = 0;
            return new FileStreamResult(fileStream, info.ContentType);
        }

        [HttpGet("{id}/{width}/{height}/view")]
        public async Task<FileStreamResult> DownloadView(string id, int width, int height)
        {
            _logger.LogError(10, "就是报个错");
            iFileService iFileService = _storageService.GetService<iFileService>(id);
            var info = await iFileService.GetFileInfoAsync();
            if (info.UploadState < 200)
            {
                return default;
            }

            var fileBytes = await iFileService.GetStreamAsync(width, height);

            this.Response.ContentLength = fileBytes.Length;
            this.Response.Headers.Add("Accept-Ranges", "bytes");
            this.Response.Headers.Add("Content-Range", "bytes 0-" + fileBytes.Length);
            return new FileStreamResult(new MemoryStream(fileBytes), info.ContentType);
        }

        [HttpGet("{queryScript}/query")]
        public async Task<IActionResult> GetAllFileDetails(string queryScript)
        {
            iFileService iFileService = _storageService.GetService<iFileService>("0");
            var files = await iFileService.QueryFileInfoAsync(queryScript);
            return Ok(files);
        }

        [HttpGet("details/{id}")]
        public async Task<IActionResult> GetFileDetails(string id)
        {
            iFileService iFileService = _storageService.GetService<iFileService>(id);
            var info = await iFileService.GetFileInfoAsync();
            return Ok(info);
        }


        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteFileAsync(string id)
        {
            iFileService iFileService = _storageService.GetService<iFileService>(id);
            await iFileService.DeleteFileAsync();
            return base.Ok($"Deleted {id} successfully");
        }

    }
}
